﻿using AutoTest.Business.IServices.Common;
using AutoTest.Common.Extension;
using AutoTest.Common;
using AutoTest.Domain;
using AutoTest.Framework.Ioc;
using EasyTool;
using AutoTest.Business.Options;

namespace AutoTest.Business.Services.Common
{
    /// <summary>
    /// 构造函数
    /// </summary>
    public class RedisCacheService(ISettingService settingService) : IRedisCacheService, IScoped
    {
        /// <summary>
        /// 每一靴的一个增长
        /// </summary>
        protected const string REDIS_XUE_INCREMENT = "xue-increment";

        /// <summary>
        /// 配置服务
        /// </summary>
        protected ISettingService _settingService = settingService;

        #region GET方法
        /// <summary>
        /// get
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object Get(string key)
        {
            return StringGet(key);
        }

        /// <summary>
        /// 取缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T Get<T>(string key)
        {
            return StringGet(key).ChangeType<T>();
        }

        /// <summary>
        /// 字符串获取缓存
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string StringGet(string key)
        {
            return RedisHelper.Get(key);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="datakey"></param>
        /// <returns></returns>
        public T HashGet<T>(string key, string datakey)
        {
            string strValue = RedisHelper.HMGet(key, datakey).FirstOrDefault()!;
            Type type = typeof(T);
            if (strValue.IsNotEmpty())
            {
                if (type.IsPrimitive)
                {
                    return (T)Convert.ChangeType(strValue, typeof(T));
                }
                else if (type.Name == typeof(string).Name)
                {
                    return (T)(strValue as object);
                }
                else
                {
                    return strValue.DeserializeJson<T>();
                }
            }

            return default!;
        }

        /// <summary>
        /// 获取配置
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public string GetSetting(string key)
        {
            return HashGet<string>(AppConsts.REDIS_HASHSET_APPSETTING, key);
        }

        /// <summary>
        /// 获取配置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetSetting<T>(string key)
        {
            return HashGet<T>(AppConsts.REDIS_HASHSET_APPSETTING, key);
        }

        #endregion

        #region SET方法
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="minutes"></param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, int minutes = 5)
        {
            //using (var helper = GetInstance())
            //{
            //    return helper.StringSet(key, value.ToJson(), new TimeSpan(0, minutes, 0));
            //}
            return RedisHelper.Set(key, value, minutes * 60);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireTime"></param>
        /// <returns></returns>
        public bool Set<T>(string key, T value, DateTime expireTime)
        {
            TimeSpan timeSpan = expireTime - DateTime.Now;
            Type type = typeof(T);
            if (type.FullName == typeof(string).FullName)
            {
                return RedisHelper.Set(key, value, (int)timeSpan.TotalSeconds);
            }
            else if (type.IsPrimitive)
            {
                return RedisHelper.Set(key, value, (int)timeSpan.TotalSeconds);
            }
            else
                return RedisHelper.Set(key, value!.ToJson(), (int)timeSpan.TotalSeconds);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="minutes"></param>
        /// <returns></returns>
        public bool Set(string key, object value, int minutes = 5)
        {
            return Set<object>(key, value, minutes);
        }

        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireTime"></param>
        /// <returns></returns>
        public bool Set(string key, object value, DateTime expireTime)
        {
            return Set<object>(key, value, expireTime);
        }

        /// <summary>
        /// HashSet方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="datakey"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool HashSet<T>(string key, string datakey, T value)
        {
            //using (var helper = GetInstance())
            //{
            //    return helper.HashSet<T>(key, datakey, value);
            //}
            return RedisHelper.HMSet(key, datakey, value);
        }


        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="expireTime"></param>
        /// <returns></returns>
        public bool StringSet(string key, string value, DateTime expireTime)
        {
            TimeSpan expire = expireTime - DateTime.Now;
            //using (var helper = GetInstance())
            //{
            //    return helper.StringSet(key, value, expire);
            //}
            return this.Set(key, value, (int)expire.TotalMinutes);
        }

        /// <summary>
        /// 设置缓存（字符粗）
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="minutes"></param>
        /// <returns></returns>
        public bool StringSet(string key, string value, int minutes = 5)
        {
            TimeSpan span = new TimeSpan(0, minutes, 0);
            //using (var helper = GetInstance())
            //{
            //    return helper.StringSet(key, value, span);
            //}
            return Set(key, value, minutes);
        }
        #endregion

        /// <summary>
        /// 检查是否存在
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool IsExist(string key)
        {
            return RedisHelper.Get(key).IsNotEmpty();

        }
        /// <summary>
        /// 自增
        /// </summary>
        /// <returns></returns>
        public async Task<long> Increment()
        {
            return await RedisHelper.IncrByAsync(REDIS_XUE_INCREMENT);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="increment"></param>
        /// <returns></returns>
        public async Task<bool> SetIncrementAsync(long increment)
        {
            return await RedisHelper.SetAsync(REDIS_XUE_INCREMENT, increment);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public async Task<T> GetAppSettingAsync<T>() where T : IDbOption
        {
            var type = typeof(T);
            string key = typeof(T).FullName??"";
            
            var setting = Activator.CreateInstance<T>();
            string optionKey = setting.OptionKey;
            if (key.IsEmpty()) return default!;
            setting = Get<T>(key);
            if (setting == null)
            {
                setting = await _settingService.GetSettingOptionAsync<T>(optionKey);
                Set(key, setting);
            }
            return setting!;
        }

    }
}
